
#import <Foundation/Foundation.h>
#import <Security/Security.h>

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone, //完全信任服务器证书；
    AFSSLPinningModePublicKey, //只比对服务器证书和本地证书的Public Key是否一致，如果一致则信任服务器证书；
    AFSSLPinningModeCertificate, //比对服务器证书和本地证书的所有内容，完全一致则信任服务器证书
};

NS_ASSUME_NONNULL_BEGIN

@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>

//返回SSL Pinning的类型，默认是AFSSLPinningModeNone
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
//保存着所有的可用于校验的证书的集合，只要在证书中任何一个校验通过。evaluateServerTrust:forDomain 就会返回true，即校验通过
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
//是否允许无效或者过期的证书，默认不允许
@property (nonatomic, assign) BOOL allowInvalidCertificates;
//是否验证证书中的域名domain 默认是yes
/*
 validatesDomainName 是否需要验证域名，默认为YES；
 假如证书的域名与你请求的域名不一致，需把该项设置为NO；
 如设成NO的话，即服务器使用其他可信任机构颁发的证书，也可以建立连接，这个非常危险，建议打开。
 置为NO，主要用于这种情况：客户端请求的是子域名，而证书上的是另外一个域名。
 因为SSL证书上的域名是独立的，假如证书上注册的域名是www.google.com，那么mail.google.com是无法验证通过的；
 当然，有钱可以注册通配符的域名*.google.com，但这个还是比较贵的。
 如置为NO，建议自己添加对应域名的校验逻辑。
 */
@property (nonatomic, assign) BOOL validatesDomainName;

//返回指定bundle的中证书，如果使用afn的证书验证 就必须实现此证书
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;

//默认的policy  不允许无效或过期的证书；验证domain域名；不对证书和公钥进行验证。
+ (instancetype)defaultPolicy;



+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;


//核心方法，参数一 服务器发放的x.509信任证书  参数二 domain 是发放信任证书的服务器域名，此方法基于security policy u来验证指定服务器是否可信任，这个方法应该在相应服务器身份验证挑战时使用
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(nullable NSString *)domain;

@end

NS_ASSUME_NONNULL_END
